package system

import (
	"context"
	"gf_blog_admin/internal/dao"
	"gf_blog_admin/internal/model"
	"gf_blog_admin/internal/service"
	"gf_blog_admin/utility/storager"
	"gf_blog_admin/utility/utils"
	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/os/gtime"
)

type sSysFile struct{}

func init() {
	service.RegisterSysFile(NewSysFile())
}

func NewSysFile() *sSysFile {
	return &sSysFile{}
}

func (s *sSysFile) List(ctx context.Context, in *model.FileListInput) (out []*model.FileListItem, total int, err error) {
	var (
		cls = dao.BlFile.Columns()
		m   = dao.BlFile.Ctx(ctx)
	)

	if in.Recycle {
		m = m.Unscoped().Where(cls.IsDeleted, 1)
	}
	if in.Keywords != "" {
		m = m.WhereLike(cls.FileName, in.Keywords+"%")
	}
	if in.Storage != "" {
		m = m.WhereLike(cls.FileStorage, in.Storage)
	}
	if in.Type != "" {
		m = m.WhereLike(cls.FileFormat, in.Type)
	}
	if in.StartDate != "" && in.EndDate != "" {
		m = m.WhereBetween(cls.CreatedAt, in.StartDate, in.EndDate)
	}

	out = make([]*model.FileListItem, 0)
	err = m.OrderDesc(cls.Id).
		Fields(
			cls.Id, cls.FileName, cls.FilePath, cls.FileFormat, cls.FileType, cls.FileSize,
			cls.FileStorage, cls.UserId, cls.GroupId, cls.CreatedAt, cls.DeletedAt,
		).
		Page(in.Page, in.PageSize).
		ScanAndCount(&out, &total, false)
	if out != nil && err == nil {
		for i, v := range out {
			out[i].FileUrl = storager.LastUrl(ctx, v.FilePath, v.FileStorage)
		}
	}
	return
}

func (s *sSysFile) Menus(ctx context.Context) (out []*model.FileMenuItem, err error) {
	out = make([]*model.FileMenuItem, 0)
	out = append(out, &model.FileMenuItem{
		Id:    0,
		Label: "默认分组",
	})
	kinds := storager.KindSlice
	for i, kind := range kinds {
		out = append(out, &model.FileMenuItem{
			Id:    uint64(i + 1),
			Label: kind,
		})
	}
	return
}

func (s *sSysFile) Destroy(ctx context.Context, ids []uint64) (err error) {
	var (
		check bool
		cls   = dao.BlFile.Columns()
		m     = dao.BlFile.Ctx(ctx).Unscoped().Where(cls.IsDeleted, 0)
	)

	ids = utils.UniqueIds(ids)
	if check, err = m.WhereIn(cls.Id, ids).Exist(); err != nil {
		return err
	} else if !check {
		return gerror.New("操作失败")
	}

	return dao.BlFile.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = m.WhereIn(cls.Id, ids).Data(map[string]interface{}{
			cls.IsDeleted: 1, cls.DeletedAt: gtime.Now(),
		}).Update()
		return err
	})
}

func (s *sSysFile) Recover(ctx context.Context, ids []uint64) (err error) {
	var (
		check bool
		cls   = dao.BlFile.Columns()
		m     = dao.BlFile.Ctx(ctx).Unscoped().Where(cls.IsDeleted, 1)
	)

	ids = utils.UniqueIds(ids)
	if check, err = m.WhereIn(cls.Id, ids).Exist(); err != nil {
		return err
	} else if !check {
		return gerror.New("操作失败")
	}

	err = dao.BlFile.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = m.WhereIn(cls.Id, ids).Data(map[string]interface{}{
			cls.IsDeleted: 0, cls.DeletedAt: nil,
		}).Update()
		return err
	})
	return
}

func (s *sSysFile) Remove(ctx context.Context, ids []uint64) (err error) {
	var (
		data []*model.FileListItem
		cls  = dao.BlFile.Columns()
		m    = dao.BlFile.Ctx(ctx).Unscoped().Where(cls.IsDeleted, 1)
	)

	ids = utils.UniqueIds(ids)
	err = m.WhereIn(cls.Id, ids).Fields(cls.FilePath, cls.FileStorage).Scan(&data)
	if err != nil {
		return err
	}
	if data == nil || len(data) == 0 {
		return gerror.New("操作失败")
	}

	err = dao.BlFile.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		if _, err = m.WhereIn(cls.Id, ids).Delete(); err != nil {
			return err
		}
		// 删除文件
		for _, v := range data {
			_ = storager.DoDestroy(ctx, v.FilePath, v.FileStorage)
		}
		return nil
	})
	return
}
